package com.learn.sqlsession.impl;

import com.learn.pojo.Configuration;
import com.learn.pojo.MappedStatement;
import com.learn.sqlsession.BoundSql;
import com.learn.sqlsession.Executor;
import com.learn.utils.GenericTokenParser;
import com.learn.utils.ParameterMapping;
import com.learn.utils.ParameterMappingTokenHandler;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class SimpleExecutor implements Executor {
    private Connection connection;

    @Override
    public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object... params) throws Exception {
        //获取连接
        connection = configuration.getDataSource().getConnection();
        //对sql进行处理
        BoundSql boundSql = getBoundSql(mappedStatement.getSql());

        String finalSql = boundSql.getSqlText();
        //获取传入参数类型
        Class<?> parameterType = getClassType(mappedStatement.getParameterType());
        //获取到预编译对象
        PreparedStatement preparedStatement = connection.prepareStatement(finalSql);
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappingList();
        for (int i = 0; i < parameterMappings.size(); i++) {
            ParameterMapping mapping = parameterMappings.get(i);
            String context = mapping.getContent();
            //允许暴力访问
            Field declaredField = parameterType.getDeclaredField(context);
            declaredField.setAccessible(true);
            //设置参数的值
            Object o = declaredField.get(params[0]);
            //给占位符赋值
            preparedStatement.setObject(i + 1, o);
        }
        //接下来查询到结果集以后 将结果集中的参数 封装到 List<resultType> 中去
        ResultSet resultSet = preparedStatement.executeQuery();
        Class<?> resultType = getClassType(mappedStatement.getResultType());
        ArrayList<Object> results = new ArrayList<>();
        while (resultSet.next()) {
            //创建一个新的对象，如果我现在传入的是User.class
            //那我就是创建new User()
            Object o = resultType.newInstance();
            ResultSetMetaData metaData = resultSet.getMetaData();
            //获取总列数
            int columnCount = metaData.getColumnCount();
            for (int i = 1; i <= columnCount; i++) {
                //属性名
                String columnName = metaData.getColumnName(i);
                //获取属性值
                Object value = resultSet.getObject(columnName);
                //创建属性描述器 为属性生成读写方法
                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultType);
                //获取写方法
                Method writeMethod = propertyDescriptor.getWriteMethod();
                //向类中写入值
                writeMethod.invoke(o, value);
            }
            results.add(o);
        }

        return (List<E>) results;
    }

    private BoundSql getBoundSql(String sql) {
        //标记处理类：主要是配合通用标记解析器GenericTokenParser类完成对配置文件等的解析工作
        ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();
        GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}", parameterMappingTokenHandler);
        String parse = genericTokenParser.parse(sql);
        List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings();
        return new BoundSql(parse, parameterMappings);
    }

    @Override
    public void close() throws SQLException {
        connection.close();
    }


    private Class<?> getClassType(String parameterType) throws ClassNotFoundException {
        if (parameterType != null) {
            return Class.forName(parameterType);
        }
        return null;
    }
}
